﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace CommonMethod
{
    public class SingleImageProcess
    {
        [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
        private static extern void CopyMemory(IntPtr Destination, IntPtr Source, [MarshalAs(UnmanagedType.U4)] int Length);

        public static Bitmap DIB2Gray(Bitmap pcBmp)
        {
            if (pcBmp.PixelFormat != PixelFormat.Format24bppRgb)
            {
                return null;
            }
            Bitmap rt = new Bitmap(pcBmp.Width, pcBmp.Height, PixelFormat.Format8bppIndexed);
            BitmapData data_src = pcBmp.LockBits(new Rectangle(0, 0, pcBmp.Width, pcBmp.Height), ImageLockMode.ReadWrite, pcBmp.PixelFormat);
            BitmapData data_dst = rt.LockBits(new Rectangle(0, 0, rt.Width, rt.Height), ImageLockMode.ReadWrite, rt.PixelFormat);
            IntPtr ipSrc = data_src.Scan0;
            IntPtr ipDst = data_dst.Scan0;

            unsafe
            {
                byte* ptrSrc = (byte*)(ipSrc);
                byte* ptrDst = (byte*)(ipDst);
                for (int i = 0; i < pcBmp.Height; i++)
                {
                    for (int j = 0; j < pcBmp.Width; j++)
                    {
                        Byte tmpR = ptrSrc[i * data_src.Stride + j * 3];
                        Byte tmpG = ptrSrc[i * data_src.Stride + j * 3 + 1];
                        Byte tmpB = ptrSrc[i * data_src.Stride + j * 3 + 2];

                        ptrDst[i * data_dst.Stride + j] = (Byte)((int)tmpR * 0.299f + (int)tmpG * 0.587f + (int)tmpB * 0.114f);
                    }
                }
            }

            rt.UnlockBits(data_dst);
            pcBmp.UnlockBits(data_src);
            return rt;
        }

        public static Bitmap CopyImage(Bitmap pcBmp)
        {
            Bitmap rt = new Bitmap(pcBmp.Width, pcBmp.Height, pcBmp.PixelFormat);
            BitmapData data_src = pcBmp.LockBits(new Rectangle(0, 0, pcBmp.Width, pcBmp.Height), ImageLockMode.ReadWrite, pcBmp.PixelFormat);
            BitmapData data_dst = rt.LockBits(new Rectangle(0, 0, rt.Width, rt.Height), ImageLockMode.ReadWrite, rt.PixelFormat);
            IntPtr ipSrc = data_src.Scan0;
            IntPtr ipDst = data_dst.Scan0;

            CopyMemory(ipDst, ipSrc, data_src.Stride * data_src.Height);

            rt.UnlockBits(data_dst);
            pcBmp.UnlockBits(data_src);
            return rt;
        }

        public static void Copy(Bitmap pcBmp, Bitmap rt)
        {
            BitmapData data_src = pcBmp.LockBits(new Rectangle(0, 0, pcBmp.Width, pcBmp.Height), ImageLockMode.ReadWrite, pcBmp.PixelFormat);
            BitmapData data_dst = rt.LockBits(new Rectangle(0, 0, rt.Width, rt.Height), ImageLockMode.ReadWrite, rt.PixelFormat);
            IntPtr ipSrc = data_src.Scan0;
            IntPtr ipDst = data_dst.Scan0;

            CopyMemory(ipDst, ipSrc, data_src.Stride * data_src.Height);

            rt.UnlockBits(data_dst);
            pcBmp.UnlockBits(data_src);
        }

        public static int[] GetGrayData(Bitmap pcBmp)
        {
            if (pcBmp.PixelFormat != PixelFormat.Format8bppIndexed)
            {
                return null;
            }
            int[] grayData = new int[pcBmp.Width * pcBmp.Height];
            BitmapData data_src = pcBmp.LockBits(new Rectangle(0, 0, pcBmp.Width, pcBmp.Height), ImageLockMode.ReadWrite, pcBmp.PixelFormat);
            IntPtr ipSrc = data_src.Scan0;

            unsafe
            {
                byte* ptrSrc = (byte*)(ipSrc);
                for (int i = 0; i < pcBmp.Height; i++)
                {
                    for (int j = 0; j < pcBmp.Width; j++)
                    {
                        Byte tmpG = ptrSrc[i * pcBmp.Width + j];
                        grayData[i * pcBmp.Width + j] = (int)tmpG;
                    }
                }
            }

            pcBmp.UnlockBits(data_src);
            return grayData;
        }

        public static void SetGrayData(Bitmap pcBmp, int[] grayData)
        {
            if (pcBmp.PixelFormat != PixelFormat.Format8bppIndexed)
            {
                return;
            }

            BitmapData data_src = pcBmp.LockBits(new Rectangle(0, 0, pcBmp.Width, pcBmp.Height), ImageLockMode.ReadWrite, pcBmp.PixelFormat);
            IntPtr ipSrc = data_src.Scan0;

            unsafe
            {
                byte* ptrSrc = (byte*)(ipSrc);
                for (int i = 0; i < pcBmp.Height; i++)
                {
                    for (int j = 0; j < pcBmp.Width; j++)
                    {
                        Byte tmpG = (Byte)grayData[i * pcBmp.Width + j];
                        ptrSrc[i * pcBmp.Width + j] = tmpG;
                    }
                }
            }

            pcBmp.UnlockBits(data_src);
            return;
        }

        public static Bitmap Gray2DIB(Bitmap pcBmp)
        {
            if (pcBmp.PixelFormat != PixelFormat.Format8bppIndexed)
            {
                return null;
            }
            Bitmap rt = new Bitmap(pcBmp.Width, pcBmp.Height, PixelFormat.Format24bppRgb);
            BitmapData data_src = pcBmp.LockBits(new Rectangle(0, 0, pcBmp.Width, pcBmp.Height), ImageLockMode.ReadWrite, pcBmp.PixelFormat);
            BitmapData data_dst = rt.LockBits(new Rectangle(0, 0, rt.Width, rt.Height), ImageLockMode.ReadWrite, rt.PixelFormat);
            IntPtr ipSrc = data_src.Scan0;
            IntPtr ipDst = data_dst.Scan0;

            unsafe
            {
                byte* ptrSrc = (byte*)(ipSrc);
                byte* ptrDst = (byte*)(ipDst);
                for (int i = 0; i < pcBmp.Height; i++)
                {
                    for (int j = 0; j < pcBmp.Width; j++)
                    {
                        Byte tmpG = ptrSrc[i * pcBmp.Width + j];
                        *ptrDst = tmpG;
                        *(ptrDst + 1) = tmpG;
                        *(ptrDst + 2) = tmpG;
                        ptrDst += 3;
                    }
                    ptrDst += data_dst.Stride - data_dst.Width * 3;
                }
            }

            rt.UnlockBits(data_dst);
            pcBmp.UnlockBits(data_src);
            return rt;
        }

        public static Image GetImage(string fileName)
        {
            Image img1 = Image.FromFile(fileName);
            Image img2 = new Bitmap(img1);
            img1.Dispose();
            return img2;
        }

        public static Image GetImage(Bitmap bmp)
        {
            Image img1 = bmp;
            Image img2 = new Bitmap(img1);
            img1.Dispose();
            return img2;
        }

        public static void SaveBmp8(Bitmap bmp8, string filePath)
        {
            if (!Directory.Exists(Path.GetDirectoryName(filePath)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(filePath));
            }
            ColorPalette cp = bmp8.Palette;
            for (int j = 0; j < cp.Entries.Length; j++)
            {
                cp.Entries[j] = Color.FromArgb(j, j, j);
            }
            bmp8.Palette = cp;
            bmp8.Save(filePath, ImageFormat.Bmp);
        }
    }
}
